/*
 * Copyright 2008-2023 dexian.vip. All rights reserved.
 * Support: http://www.dexian.vip
 * License: http://www.dexian.vip/license
 */

package vip.dexian.common.utils;

import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;

/**
 * 数字工具类
 *
 * @author 挺好的 2023年05月30日 16:26
 */
public final class NumberUtils {

    private NumberUtils () {
    }

    /**
     * 判断给定整数是否是正数
     *
     * @param value
     *         整数
     * @param isStrictly
     *         是否是严格模式，如果是， 0将被视为无效值。
     *
     * @return 严格模式下，大于0的整数返回true，否则返回false，
     * 非严格模式下大于等于0的整数返回true，否则返回false
     */
    public static boolean isPositive (Integer value, boolean isStrictly) {

        if (value == null) {
            return false;
        }

        int signum = Integer.signum(value);

        return isStrictly ? signum > 0 : signum >= 0;
    }

    /**
     * 判断给定整数是否是正数
     *
     * @param value
     *         整数
     *
     * @return 如果value == null，返回false。否则返回指定int值的signum函数。 （如果指定的值为负，则返回值为-1；如果指定的值为零，则返回0；如果指定的值为正，则返回1。
     */
    public static boolean isPositive (Integer value) {
        return isPositive(value, true);
    }

    /**
     * 判断给定整数是否是正数
     *
     * @param value
     *         整数
     *
     * @return 如果value == null，返回false。否则返回指定int值的signum函数。 （如果指定的值为负，则返回值为-1；如果指定的值为零，则返回0；如果指定的值为正，则返回1。
     */
    public static boolean isPositive (Long value) {

        if (value == null) {
            return false;
        }

        return Long.signum(value) > 0;
    }

    /**
     * 是否是double
     *
     * @param value
     *         值
     *
     * @return 如果value == null，返回false. 如果value > 0 返回true
     */
    public static boolean isPositive (Double value) {
        if (value == null) {
            return false;
        }

        return value > 0;
    }

    /**
     * 转换为long
     *
     * @param value
     *         值
     * @param defaultValue
     *         默认值
     *
     * @return 当值为空时，返回的默认值
     */
    public static Long toLong (Long value, Long defaultValue) {
        if (value == null) {
            return defaultValue;
        }

        return value;
    }

    /**
     * 将object 转换为 Long类型
     *
     * @param value
     *         待转换的值
     *
     * @return 如果value == null 或者不是 long类型， 返回0L
     */
    public static Long toLong (Object value) {
        if (value instanceof Long longValue) {
            return longValue;
        }

        return 0L;
    }

    /**
     * 转换double，
     *
     * @param value
     *         值， value
     * @param defaultValue
     *         默认值
     *
     * @return 如果value == null，返回defaultDouble，否则返回value
     */
    public static Double defaultDouble (Double value, double defaultValue) {
        if (value == null) {
            return defaultValue;
        }

        return value;
    }

    /**
     * 转换为long，如果value 为 空，返回defaultValue
     *
     * @param value
     *         值， value
     * @param defaultValue
     *         默认值
     *
     * @return 如果value == null ，返回defaultValue，否则返回value
     */
    public static Long defaultLong (Long value, long defaultValue) {
        if (value == null) {
            return defaultValue;
        }

        return value;
    }

    /**
     * 转换为long， defaultValue 为 0
     *
     * @param value
     *         值
     *
     * @return 如果value==null，返回0，否则返回value
     */
    public static Long defaultLong (Long value) {
        return defaultLong(value, 0L);
    }

    /**
     * list 求和
     *
     * @param values
     *         待求和的长整型数字
     *
     * @return 数字之和
     */
    public static Long sum (Long... values) {
        return Arrays.stream(values).mapToLong(NumberUtils::defaultLong).sum();
    }

    /**
     * 字符串转换为数字
     *
     * @param value
     *         字符串
     *
     * @return 转换后的数字，无法转换或者字符串为空，返回0
     */
    public static Long convertToLong (String value) {
        return convertToLong(value, 0L);
    }

    /**
     * 字符串转换为数字
     *
     * @param value
     *         字符串
     * @param defaultValue
     *         默认值
     *
     * @return 转换后的数字，无法转换或者字符串为空，返回默认值
     */
    public static Long convertToLong (String value, Long defaultValue) {

        if (StringUtils.isEmpty(value)) {
            return defaultValue;
        }

        try {
            return Long.parseLong(value);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * 两个长整型数字是否相等
     *
     * @param source
     *         源
     * @param target
     *         目标
     *
     * @return source == null || target == null，return false。 如果source和target分别在LongCache中，使用==比较，否则使用equals比较
     */
    public static boolean equals (Long source, Long target) {

        if (source == null || target == null) {
            return false;
        }

        // 在缓存内
        if ((source >= -128 && source <= 127) && (target >= -128 && target <= 127)) {
            return source == target;
        }

        return source.equals(target);
    }

    /**
     * 两个整型数字是否相等
     *
     * @param source
     *         源
     * @param target
     *         目标
     *
     * @return source == null || target == null，return false。 如果source和target分别在IntegerCache中，使用==比较，否则使用equals比较
     */
    public static boolean equals (Integer source, Integer target) {
        if (source == null || target == null) {
            return false;
        }

        if (source == target) {
            return true;
        }

        return source.equals(target);
    }

    /**
     * 高精度浮点型，保留两位小数。四舍五入
     *
     * @param value
     *         转换的值
     *
     * @return 如果value == null ，返回0
     */
    public static BigDecimal setScale (BigDecimal value) {
        return setScale(value, RoundingMode.HALF_UP);
    }

    /**
     * 高精度浮点型，保留两位小数
     *
     * @param value
     *         转换的值
     * @param roundingMode
     *         小数保留模式
     *
     * @return 如果value == null ，返回0
     */
    public static BigDecimal setScale (BigDecimal value, RoundingMode roundingMode) {
        if (value != null) {
            return value.setScale(2, roundingMode);
        } else {
            return BigDecimal.ZERO;
        }
    }
}
